#include <cmath>
#include "structs.h"
#include "gmp.h"

bool point::operator ==(const point& p) const
{
    return (x == p.x) && (y == p.y);
}

bool point::operator !=(const point& p) const
{
    return (!(*this == p));
}

bool point::operator <(const point& a) const
{
    return ((x < a.x) || ((x == a.x) && (y < a.y)));
}

bool point::operator <=(const point& a) const
{
    return ((*this < a) || (*this == a));
}

bool segment::operator ==(const segment& p) const
{
    return (first == p.first) && (second == p.second);
}

circle::circle(const point& a)
{
    boundaries = std::vector<point>();
    boundaries.push_back(a);
}

circle::circle(const point& a, const point& b)
{
    boundaries = std::vector<point>();
    boundaries.push_back(a); boundaries.push_back(b);
}

circle::circle(const point& a, const point& b, const point& c)
{
    boundaries = std::vector<point>();
    boundaries.push_back(a); boundaries.push_back(b); boundaries.push_back(c);

    double bc = sqrhypot(b,c);
    double ac = sqrhypot(a,c);
    double ab = sqrhypot(a,b);

    if (bc + ac < ab)
    {
        boundaries.erase(boundaries.begin() + 2);
    } else if (bc + ab < ac)
    {
        boundaries.erase(boundaries.begin() + 1);
    } else if (ac + ab < bc)
    {
        boundaries.erase(boundaries.begin());
    }
}

segment::segment(const point& a, const point& b)
{
    if (a.x > b.x)
    {
        second = a; first = b;
    } else
    {
        first = a; second = b;
    }

    if (second.x == first.x) {
        slope = std::numeric_limits<double>::infinity();
    } else {
        slope = (second.y - first.y) / (second.x - first.x);
        y_intercept = first.y - slope * first.x;
    }
}

bool segment::intersects_with_x(int x) const
{
    return (x >= first.x) && (x <= second.x);
}

template <class T>
void segment::y_at(int x, T& result) const
{
    if (slope = std::numeric_limits<double>::infinity())
    {
        result = std::numeric_limits<double>::infinity();
    } else
    {
        T a_x(this->first.x), b_x(this->second.x), a_y(this->first.y), b_y(this->second.y);
        T x0(x);

        result = (a_y * (b_x - x0) + b_y * (x0 - a_x)) / (b_x - a_x);
    }
}